package com.zhz.springmvc.context;

import com.zhz.springmvc.annotation.Autowired;
import com.zhz.springmvc.annotation.Controller;
import com.zhz.springmvc.annotation.Service;
import com.zhz.springmvc.xml.XmlParse;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author ：zhz
 * @date ：Created in 2021/01/03
 * @version: V1.0
 * @slogan: 天下风云出我辈，一入代码岁月催
 * @description: SpringMVC容器
 **/
public class WebApplicationContext {

    //classpath:springmvc.xml
    String contextConfigLocation;

    //定义集合  用于存放 bean 的权限名|包名.类名
    List<String> classNameList = new ArrayList<>();

    //创建Map集合用于扮演IOC容器：  key存放bean的名字   value存放bean实例
    public Map<String, Object> iocMap = new ConcurrentHashMap<>();

    public WebApplicationContext() {
    }

    public WebApplicationContext(String contextConfigLocation) {
        this.contextConfigLocation = contextConfigLocation;
    }

    /**
     * 初始化Spring容器
     */
    public void onRefresh() {
        //1、进行解析spring mvc配置文件操作  ==》 com.zhz.controller,com.zhz.service
        String basePackage = XmlParse.getBasePackage(contextConfigLocation.split(":")[1]);
        //通过"，"来分割com.zhz.controller,com.zhz.service 获得对应的包名
        String[] packs = basePackage.split(",");
        //2、进行包扫描
        for (String pack : packs) {
            executeScanPackage(pack);
        }
        //3、实例化容器中的bean
        executeInstance();

        //4、进行自动注入操作
        executeAutowired();
    }

    /**
     * 进行包扫描
     *
     * @param pack
     */
    private void executeScanPackage(String pack) {
        //1、把com.zhz.controller====>com/zhz/controller   com.zhz.service====>com/zhz/controller
        URL url = this.getClass().getClassLoader().getResource("/" + pack.replaceAll("\\.", "/"));
        String path = url.getFile();
        //2、/com/zhz/service
        File dir = new File(path);
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {//说明是com.zhz.service.impl层
                executeScanPackage(pack + "." + file.getName());
            } else {
                //文件目录下文件  获取全路径   UserController.class  ==> com.zhz.controller.UserController
                String className = pack + "." + file.getName().replaceAll(".class", "");
                classNameList.add(className);
            }
        }

    }

    /**
     * 实例化容器
     */
    private void executeInstance() {
        try {
            // com.zhz.controller.UserController      com.zhz.service.impl.UserServiceImpl
            for (String className : classNameList) {
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Controller.class)) {
                    //控制层的bean,得到类的简写名称也就是UserController
                    String beanName = clazz.getSimpleName().substring(0, 1).toLowerCase()+clazz.getSimpleName().substring(1);//首位变为小写
                    iocMap.put(beanName, clazz.newInstance());
                } else if (clazz.isAnnotationPresent(Service.class)) {
                    //Service层，主要是为了获得他的value
                    Service service = clazz.getAnnotation(Service.class);
                    String beanName = service.value();
                    iocMap.put(beanName, clazz.newInstance());
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    /**
     * 进行自动注入操作
     */
    private void executeAutowired() {
        try {
            //从容器中取出bean，然后判断bean中是否有属性上使用Autowired，如果使用了该注解，就需要进行自动注入操作
            for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
                //取出容器中的bean
                Object bean = entry.getValue();
                //从bean中获取属性
                Field[] fields = bean.getClass().getDeclaredFields();
                for (Field field : fields) {
                    if (field.isAnnotationPresent(Autowired.class)) {
                        //获取注解中的value值,该值是bean的name
                        Autowired autowired = field.getAnnotation(Autowired.class);
                        String beanName = autowired.value();
                        ;
                        //取消检查机制
                        field.setAccessible(true);
                        field.set(bean, iocMap.get(beanName));
                    }
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
